import type { WindowController } from '#/browser/controllers/window.controller'
import type { Tab } from '#/browser/entities/tab.entity'
import type { TabManager } from '#/browser/managers/tab.manager'
import type { BaseWindow, WebContentsView } from 'electron'
import { calculateWindowDimensions } from '#/utils/paths'
import { WINDOW_STYLE_CONSTANTS } from '~shared/constants/layout'
import { animateBounds } from '#/utils/animate-bounds'

/**
 * 视图层级控制器
 *
 * 负责管理窗口内所有视图的层级关系、定位和显示状态
 * 有两种顺序（从底到顶）：
 * - 布局视图在底层时：layoutView -> tabView -> sidebarView
 * - 布局视图在顶层时：tabView -> sidebarView -> layoutView
 * 注意：sidebarView 永远在 tabView 的上面（层级更高）
 * 提供统一的视图管理接口，抽象化 addChildView/removeChildView 操作
 */
export class ViewLayerController {
  private readonly electronWindow: BaseWindow
  private readonly layoutView: WebContentsView
  private readonly tabManager: TabManager
  private readonly isMainWindow: boolean
  private mainTab?: Tab
  private rightTabs: Tab[] = []
  private layoutViewIsTop = false
  // 视图与视图边框的宽度
  private readonly viewBorderWidth = 2

  // 最近一次边栏右侧标签数量变化
  private rightRecord? = {
    delta: 0, // 最近一次边栏右侧标签数量变化（>0 新增，<0 减少）
    added: [] as number[], // 最近一次添加的标签页ID
    removed: [] as number[] // 最近一次删除的标签页ID
  }

  // 动画过渡时间
  private readonly transitionDuration = 220

  /**
   * 构造函数
   * @param window - 窗口控制器实例
   */
  constructor(private readonly window: WindowController) {
    this.electronWindow = this.window.electronWindow
    this.layoutView = this.window.layoutTab.view
    this.tabManager = this.window.tabManager
    this.isMainWindow = this.window.isMainWindow
    this.setupWindowEventListeners()
    this.setLayoutView()
    // 初始化当前可见视图（如果已存在）并计算边界
    this.setMainTab()
    this.setRightTab()
    this.handleWindowResize()
  }

  onHandleWindowResize = this.handleWindowResize.bind(this)
  // 视图切换
  viewChange = (type: string) => {
    if (type === 'right') {
      this.setRightTab()
    } else {
      this.setMainTab()
    }
    this.handleWindowResize(type === 'right')
  }

  onViewChange = this.viewChange.bind(this)
  /**
   * 设置窗口事件监听器
   *
   * @private
   * @description 注册窗口生命周期和状态变化的事件监听器，
   *              包括关闭、移动、调整大小和最大化事件
   */
  private setupWindowEventListeners(): void {
    // 监听窗口尺寸变化，统一更新边界
    this.electronWindow.on('resize', this.onHandleWindowResize)
    this.electronWindow.on('maximize', this.onHandleWindowResize)
    this.electronWindow.on('unmaximize', this.onHandleWindowResize)

    // 监听视图变化：先调整层级，再更新可见视图的边界
    this.tabManager.on('view-changed', this.onViewChange)

    this.electronWindow.focus()
  }

  /**
   * 设置布局视图层级
   * @param isTop - 是否将布局视图移动到顶层，默认为底层
   */
  setLayoutView(isTop = false): void {
    if (isTop) {
      // 移动到顶层（最后添加的视图在最上层）
      this.electronWindow.contentView.addChildView(this.layoutView)
      this.layoutViewIsTop = true
    } else {
      // 移动到底层（索引0为最底层）
      this.electronWindow.contentView.addChildView(this.layoutView, 0)
      this.layoutViewIsTop = false
    }
  }

  /**
   * 设置标签页视图
   */
  setMainTab(): void {
    // 移除旧的标签页视图
    const activeTab = this.tabManager.activeTab?.tab
    if (this.mainTab === activeTab) return

    if (this.mainTab) {
      this.electronWindow.contentView.removeChildView(this.mainTab.view)
      // 解绑旧的事件
      const h = this.fullscreenHandlers.get(this.mainTab)
      if (h) {
        this.mainTab.off('fullscreen:change', h)
        this.fullscreenHandlers.delete(this.mainTab)
      }
    }

    this.mainTab = activeTab
    if (!activeTab) {
      return
    }

    const h = this.fullscreenChange.bind(this, activeTab)
    this.fullscreenHandlers.set(activeTab, h)
    activeTab.on('fullscreen:change', h)

    // 计算正确的插入位置
    const insertIndex = this.calculateTabViewIndex()
    this.electronWindow.contentView.addChildView(activeTab.view, insertIndex)
  }

  private rightWidthHandlers = new WeakMap<Tab, () => void>()
  private fullscreenHandlers = new WeakMap<Tab, () => void>()

  /**
   * 处理标签页全屏状态变化
   * @param tab - 发生全屏状态变化的标签页
   */
  fullscreenChange(tab: Tab): void {
    // 检查是否是当前活动的标签页
    const isMainTab = this.mainTab === tab
    const isRightTab = this.rightTabs.includes(tab)

    if (!isMainTab && !isRightTab) {
      // 如果不是当前显示的标签页，不处理
      return
    }

    // 根据全屏状态调整视图边界
    if (tab.htmlFullScreen) {
      // 进入全屏：将标签页视图移到最顶层
      this.electronWindow.contentView.addChildView(tab.view) // 添加到最后，即最顶层
      this.updateFullscreenBounds(tab)
    } else {
      this.handleWindowResize()
    }
  }

  /**
   * 更新全屏模式下的视图边界
   * @param tab - 全屏的标签页
   */
  private updateFullscreenBounds(tab: Tab): void {
    try {
      if (this.electronWindow.isDestroyed() || tab.view.webContents.isDestroyed()) {
        console.warn('尝试更新已销毁的视图边界')
        return
      }

      const { width, height } = calculateWindowDimensions(this.electronWindow)

      // 全屏模式下，视图占满整个窗口，不留边距
      tab.view.setBounds({
        x: 0,
        y: 0,
        width,
        height
      })

      // 聚焦全屏视图
      if (!this.electronWindow.isFocused()) {
        this.electronWindow.focus()
      }
    } catch (error) {
      console.error('更新全屏视图边界时发生错误:', error)
    }
  }

  timeountIds = [] as NodeJS.Timeout[]

  /**
   * 设置边栏视图
   */
  setRightTab(): void {
    const activeTabs = this.tabManager.activeRightTabs

    if (
      activeTabs.length == this.rightTabs.length &&
      activeTabs.every(tab => this.rightTabs.includes(tab))
    ) {
      return
    }

    // 记录具体差异：增加/移除的 ID 列表

    const prevIds = new Set(this.rightTabs.map(t => t.data.id))
    const nextIds = new Set(activeTabs.map(t => t.data.id))

    this.rightRecord = {
      delta: activeTabs.length - this.rightTabs.length,
      added: Array.from(nextIds).filter(id => !prevIds.has(id)),
      removed: Array.from(prevIds).filter(id => !nextIds.has(id))
    }

    // 解绑旧
    for (const tab of this.rightTabs) {
      const h = this.rightWidthHandlers.get(tab)
      if (h) {
        tab.off('width:change', h)
        this.rightWidthHandlers.delete(tab)
      }

      const fh = this.fullscreenHandlers.get(tab)
      if (fh) {
        tab.off('fullscreen:change', fh)
        this.fullscreenHandlers.delete(tab)
      }
    }

    // 绑定新
    for (const tab of activeTabs) {
      const h = this.handleWindowResize.bind(this, false)
      const fh = this.fullscreenChange.bind(this, tab)
      this.rightWidthHandlers.set(tab, h)
      this.fullscreenHandlers.set(tab, fh)
      tab.on('width:change', h)
      tab.on('fullscreen:change', fh)
    }

    // 移除旧的边栏视图
    if (this.rightTabs.length > 0) {
      for (const v of this.rightTabs) {
        if (v) {
          this.electronWindow.contentView.removeChildView(v.view)
        }
      }
    }

    this.rightTabs = activeTabs

    if (activeTabs.length === 0) {
      return
    }
    this.timeountIds.forEach(clearTimeout)
    this.timeountIds = []
    // 计算正确的插入位置
    const insertIndex = this.calculateSidebarViewIndex()
    for (const v of activeTabs) {
      if (
        this.rightRecord.added.includes(v.data.id) &&
        this.rightRecord.delta > 0 &&
        this.mainTab
      ) {
        this.timeountIds.push(
          setTimeout(() => {
            this.electronWindow.contentView.addChildView(v.view, insertIndex)
          }, this.transitionDuration + 50)
        )
      } else {
        this.electronWindow.contentView.addChildView(v.view, insertIndex)
      }
    }
  }

  /**
   * 计算标签页视图的插入位置
   * @returns 插入位置索引
   */
  private calculateTabViewIndex(): number {
    if (this.layoutViewIsTop) {
      // 布局视图在顶层时：tabView -> sidebarView(可选) -> layoutView
      return 0
    } else {
      // 布局视图在底层时：layoutView -> tabView -> sidebarView(可选)
      return 1
    }
  }

  /**
   * 计算边栏视图的插入位置
   * @returns 插入位置索引
   */
  private calculateSidebarViewIndex(): number {
    if (this.layoutViewIsTop) {
      // 布局视图在顶层时：mainTab(可选) -> rightTab -> layoutView
      return this.mainTab ? 1 : 0
    } else {
      // 布局视图在底层时：layoutView -> mainTab(可选) -> rightTab
      return this.mainTab ? 2 : 1
    }
  }

  private get mainViewTop() {
    const { TOP_HEIGHT, SEARCH_BAR_HEIGHT } = WINDOW_STYLE_CONSTANTS
    const activeTab = this.tabManager.activeTab
    const hideAddressBarTop = TOP_HEIGHT - SEARCH_BAR_HEIGHT + 4
    if (!activeTab) return hideAddressBarTop

    return TOP_HEIGHT
  }

  private get rightViewTop() {
    const { RIGHT_HEADER_HEIGHT, TOP_HEIGHT, SEARCH_BAR_HEIGHT } = WINDOW_STYLE_CONSTANTS

    return TOP_HEIGHT - SEARCH_BAR_HEIGHT + 4 + RIGHT_HEADER_HEIGHT
  }

  /**
   * 更新主视图的边界位置，仅对“已显示”的主标签页生效
   * @param animate 开启动画
   */
  updateMainViewBounds(animate?: boolean): void {
    try {
      const activeTab = this.tabManager.activeTab
      if (!activeTab) return
      const tab = activeTab.tab

      // 检查窗口和视图是否已销毁
      if (this.electronWindow.isDestroyed() || tab.view.webContents.isDestroyed()) {
        console.warn('尝试更新已销毁的视图边界')
        return
      }

      const { width, height } = calculateWindowDimensions(this.electronWindow)
      const { LEFT_WIDTH, RIGHT_WIDTH, VIEW_BORDER_WIDTH } = WINDOW_STYLE_CONSTANTS

      const leftOffset = this.isMainWindow ? LEFT_WIDTH : 0

      let tabWidth = width - leftOffset

      // 保留右侧固定占位宽度与各右侧视图宽度
      tabWidth -= RIGHT_WIDTH
      const rightTabs = this.tabManager.activeRightTabs
      const rightTabWidth = rightTabs.reduce(
        (total, t) => total + t.sidebarWidth + VIEW_BORDER_WIDTH,
        0
      )
      if (rightTabWidth) {
        tabWidth -= rightTabWidth
      }

      // 全屏模式不留白
      const padding = VIEW_BORDER_WIDTH

      animateBounds(
        tab.view,
        {
          x: leftOffset + padding,
          y: this.mainViewTop,
          width: tabWidth - padding,
          height: height - this.mainViewTop - padding
        },
        { enabled: animate, duration: this.transitionDuration }
      )
    } catch (error) {
      console.error('更新视图边界时发生错误:', error)
    }
  }

  /**
   * 更新右侧边栏视图边界，仅对“已显示”的右侧标签页生效
   */
  updateRightViewBounds(): void {
    try {
      const tabs = this.rightTabs
      if (tabs?.length === 0) return

      // 检查窗口和视图是否已销毁
      if (
        this.electronWindow.isDestroyed() ||
        tabs.some(tab => tab.view.webContents.isDestroyed())
      ) {
        console.warn('尝试更新已销毁的视图边界')
        return
      }

      const { width, height } = calculateWindowDimensions(this.electronWindow)
      const { RIGHT_WIDTH, VIEW_BORDER_WIDTH } = WINDOW_STYLE_CONSTANTS

      tabs.reduceRight((rightOffset, tab, index) => {
        const tabWidth = tab.sidebarWidth
        let x = width - rightOffset - tabWidth + this.viewBorderWidth
        if (index < tabs.length - 1) {
          x += VIEW_BORDER_WIDTH - this.viewBorderWidth * 2 - 1
        } else {
          x += 1
        }
        tab.view.setBounds({
          x,
          y: this.rightViewTop,
          width: tabWidth - this.viewBorderWidth * 2,
          height: height - this.rightViewTop - VIEW_BORDER_WIDTH - this.viewBorderWidth / 2
        })
        return rightOffset + tabWidth + VIEW_BORDER_WIDTH
      }, RIGHT_WIDTH as number)
      this.rightRecord = void 0
    } catch (error) {
      console.error('更新视图边界时发生错误:', error)
    }
  }

  /**
   * 统一处理窗口尺寸变化：更新布局、主视图与右侧视图边界
   * @param animate 开启动画
   */
  private handleWindowResize(animate?: boolean) {
    this.updateLayoutViewBounds()
    this.updateMainViewBounds(animate)
    this.updateRightViewBounds()
    if (!this.electronWindow.isFocused()) {
      this.electronWindow.focus()
    }
  }

  // 更新布局视图边界
  private updateLayoutViewBounds() {
    try {
      if (this.electronWindow.isDestroyed()) return

      const { width, height } = calculateWindowDimensions(this.electronWindow)

      if (this.window.layoutTab && !this.window.layoutTab.view.webContents.isDestroyed()) {
        this.window.layoutTab.view.setBounds({ x: 0, y: 0, width, height })
      }
    } catch (error) {
      console.error('更新视图边界时发生错误:', error)
    }
  }

  /**
   * 清理资源和事件监听器
   */
  cleanup(): void {
    this.electronWindow.removeListener('move', this.onHandleWindowResize)
    this.electronWindow.removeListener('resize', this.onHandleWindowResize)
    this.electronWindow.removeListener('maximize', this.onHandleWindowResize)
    this.electronWindow.removeListener('unmaximize', this.onHandleWindowResize)

    this.tabManager.removeListener('view-changed', this.onViewChange)
  }
}
